home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / yacc / flexyacc / aflex.lha / aflex / src / dfaB.a < prev    next >
Text File  |  1991-05-16  |  30KB  |  942 lines

  1. -- Copyright (c) 1990 Regents of the University of California.
  2. -- All rights reserved.
  3. --
  4. -- This software was developed by John Self of the Arcadia project
  5. -- at the University of California, Irvine.
  6. --
  7. -- Redistribution and use in source and binary forms are permitted
  8. -- provided that the above copyright notice and this paragraph are
  9. -- duplicated in all such forms and that any documentation,
  10. -- advertising materials, and other materials related to such
  11. -- distribution and use acknowledge that the software was developed
  12. -- by the University of California, Irvine.  The name of the
  13. -- University may not be used to endorse or promote products derived
  14. -- from this software without specific prior written permission.
  15. -- THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16. -- IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17. -- WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  
  19. -- TITLE DFA construction routines
  20. -- AUTHOR: John Self (UCI)
  21. -- DESCRIPTION converts non-deterministic finite automatons to finite ones.
  22. -- $Header: /co/ua/self/arcadia/aflex/ada/src/RCS/dfaB.a,v 1.18 90/01/12 15:19:48 self Exp Locker: self $ 
  23.  
  24. with DFA, INT_IO, MISC_DEFS, TEXT_IO, MISC, TBLCMP, CCL, EXTERNAL_FILE_MANAGER; 
  25. with ECS, NFA, TSTRING, GEN, SKELETON_MANAGER; use MISC_DEFS, 
  26.   EXTERNAL_FILE_MANAGER; 
  27.  
  28. package body DFA is 
  29.   use TSTRING; 
  30.   -- check_for_backtracking - check a DFA state for backtracking
  31.   --
  32.   -- ds is the number of the state to check and state[) is its out-transitions,
  33.   -- indexed by equivalence class, and state_rules[) is the set of rules
  34.   -- associated with this state
  35.  
  36.   DID_STK_INIT : BOOLEAN := FALSE; 
  37.   STK          : INT_PTR; 
  38.  
  39.   procedure CHECK_FOR_BACKTRACKING(DS    : in INTEGER; 
  40.                                    STATE : in UNBOUNDED_INT_ARRAY) is 
  41.     use MISC_DEFS; 
  42.   begin
  43.     if (DFAACC(DS).DFAACC_STATE = 0) then 
  44.  
  45.       -- state is non-accepting
  46.       NUM_BACKTRACKING := NUM_BACKTRACKING + 1; 
  47.  
  48.       if (BACKTRACK_REPORT) then 
  49.         TEXT_IO.PUT(BACKTRACK_FILE, "State #"); 
  50.         INT_IO.PUT(BACKTRACK_FILE, DS, 1); 
  51.         TEXT_IO.PUT(BACKTRACK_FILE, "is non-accepting -"); 
  52.         TEXT_IO.NEW_LINE(BACKTRACK_FILE); 
  53.  
  54.         -- identify the state
  55.         DUMP_ASSOCIATED_RULES(BACKTRACK_FILE, DS); 
  56.  
  57.         -- now identify it further using the out- and jam-transitions
  58.         DUMP_TRANSITIONS(BACKTRACK_FILE, STATE); 
  59.         TEXT_IO.NEW_LINE(BACKTRACK_FILE); 
  60.       end if; 
  61.     end if; 
  62.   end CHECK_FOR_BACKTRACKING; 
  63.  
  64.  
  65.   -- check_trailing_context - check to see if NFA state set constitutes
  66.   --                          "dangerous" trailing context
  67.   --
  68.   -- NOTES
  69.   --    Trailing context is "dangerous" if both the head and the trailing
  70.   --  part are of variable size \and/ there's a DFA state which contains
  71.   --  both an accepting state for the head part of the rule and NFA states
  72.   --  which occur after the beginning of the trailing context.
  73.   --  When such a rule is matched, it's impossible to tell if having been
  74.   --  in the DFA state indicates the beginning of the trailing context
  75.   --  or further-along scanning of the pattern.  In these cases, a warning
  76.   --  message is issued.
  77.   --
  78.   --    nfa_states[1 .. num_states) is the list of NFA states in the DFA.
  79.   --    accset[1 .. nacc) is the list of accepting numbers for the DFA state.
  80.  
  81.   procedure CHECK_TRAILING_CONTEXT(NFA_STATES : in INT_PTR; 
  82.                                    NUM_STATES : in INTEGER; 
  83.                                    ACCSET     : in INT_PTR; 
  84.                                    NACC       : in INTEGER) is 
  85.     NS, AR              : INTEGER; 
  86.     STATE_VAR, TYPE_VAR : STATE_ENUM; 
  87.  
  88.     use MISC_DEFS, MISC, TEXT_IO; 
  89.   begin
  90.     for I in 1 .. NUM_STATES loop
  91.       NS := NFA_STATES(I); 
  92.       TYPE_VAR := STATE_TYPE(NS); 
  93.       AR := ASSOC_RULE(NS); 
  94.  
  95.       if ((TYPE_VAR = STATE_NORMAL) or (RULE_TYPE(AR) /= RULE_VARIABLE)) then 
  96.         null; 
  97.  
  98.       -- do nothing
  99.       else 
  100.         if (TYPE_VAR = STATE_TRAILING_CONTEXT) then 
  101.  
  102.           -- potential trouble.  Scan set of accepting numbers for
  103.           -- the one marking the end of the "head".  We assume that
  104.           -- this looping will be fairly cheap since it's rare that
  105.           -- an accepting number set is large.
  106.           for J in 1 .. NACC loop
  107.             if (CHECK_YY_TRAILING_HEAD_MASK(ACCSET(J)) /= 0) then 
  108.               TEXT_IO.PUT(STANDARD_ERROR, 
  109.                 "aflex: Dangerous trailing context in rule at line "); 
  110.               INT_IO.PUT(STANDARD_ERROR, RULE_LINENUM(AR), 1); 
  111.               TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  112.               return; 
  113.             end if; 
  114.           end loop; 
  115.         end if; 
  116.       end if; 
  117.     end loop; 
  118.   end CHECK_TRAILING_CONTEXT; 
  119.  
  120.  
  121.   -- dump_associated_rules - list the rules associated with a DFA state
  122.   --
  123.   -- goes through the set of NFA states associated with the DFA and
  124.   -- extracts the first MAX_ASSOC_RULES unique rules, sorts them,
  125.   -- and writes a report to the given file
  126.  
  127.   procedure DUMP_ASSOCIATED_RULES(F  : in FILE_TYPE; 
  128.                                   DS : in INTEGER) is 
  129.     J                    : INTEGER; 
  130.     NUM_ASSOCIATED_RULES : INTEGER := 0; 
  131.     RULE_SET             : INT_PTR; 
  132.     SIZE, RULE_NUM       : INTEGER; 
  133.   begin
  134.     RULE_SET := new UNBOUNDED_INT_ARRAY(0 .. MAX_ASSOC_RULES + 1); 
  135.     SIZE := DFASIZ(DS); 
  136.  
  137.     for I in 1 .. SIZE loop
  138.       RULE_NUM := RULE_LINENUM(ASSOC_RULE(DSS(DS)(I))); 
  139.  
  140.       J := 1; 
  141.       while (J <= NUM_ASSOCIATED_RULES) loop
  142.         if (RULE_NUM = RULE_SET(J)) then 
  143.           exit; 
  144.         end if; 
  145.         J := J + 1; 
  146.       end loop; 
  147.       if (J > NUM_ASSOCIATED_RULES) then 
  148.  
  149.         --new rule
  150.         if (NUM_ASSOCIATED_RULES < MAX_ASSOC_RULES) then 
  151.           NUM_ASSOCIATED_RULES := NUM_ASSOCIATED_RULES + 1; 
  152.           RULE_SET(NUM_ASSOCIATED_RULES) := RULE_NUM; 
  153.         end if; 
  154.       end if; 
  155.     end loop; 
  156.  
  157.     MISC.BUBBLE(RULE_SET, NUM_ASSOCIATED_RULES); 
  158.  
  159.     TEXT_IO.PUT(F, " associated rules:"); 
  160.  
  161.     for I in 1 .. NUM_ASSOCIATED_RULES loop
  162.       if (I mod 8 = 1) then 
  163.         TEXT_IO.NEW_LINE(F); 
  164.       end if; 
  165.  
  166.       TEXT_IO.PUT(F, ASCII.HT); 
  167.       INT_IO.PUT(F, RULE_SET(I), 1); 
  168.     end loop; 
  169.  
  170.     TEXT_IO.NEW_LINE(F); 
  171.   exception
  172.     when STORAGE_ERROR => 
  173.       MISC.AFLEXFATAL("dynamic memory failure in dump_associated_rules()"); 
  174.   end DUMP_ASSOCIATED_RULES; 
  175.  
  176.  
  177.   -- dump_transitions - list the transitions associated with a DFA state
  178.   --
  179.   -- goes through the set of out-transitions and lists them in human-readable
  180.   -- form (i.e., not as equivalence classes); also lists jam transitions
  181.   -- (i.e., all those which are not out-transitions, plus EOF).  The dump
  182.   -- is done to the given file.
  183.  
  184.   procedure DUMP_TRANSITIONS(F     : in FILE_TYPE; 
  185.                              STATE : in UNBOUNDED_INT_ARRAY) is 
  186.     EC           : INTEGER; 
  187.     OUT_CHAR_SET : C_SIZE_BOOL_ARRAY; 
  188.   begin
  189.     for I in 1 .. CSIZE loop
  190.       EC := ECGROUP(I); 
  191.  
  192.       if (EC < 0) then 
  193.         EC :=  -EC; 
  194.       end if; 
  195.  
  196.       OUT_CHAR_SET(I) := (STATE(EC) /= 0); 
  197.     end loop; 
  198.  
  199.     TEXT_IO.PUT(F, " out-transitions: "); 
  200.  
  201.     CCL.LIST_CHARACTER_SET(F, OUT_CHAR_SET); 
  202.  
  203.     -- now invert the members of the set to get the jam transitions
  204.     for I in 1 .. CSIZE loop
  205.       OUT_CHAR_SET(I) := not OUT_CHAR_SET(I); 
  206.     end loop; 
  207.  
  208.     TEXT_IO.NEW_LINE(F); 
  209.     TEXT_IO.PUT(F, "jam-transitions: EOF "); 
  210.  
  211.     CCL.LIST_CHARACTER_SET(F, OUT_CHAR_SET); 
  212.  
  213.     TEXT_IO.NEW_LINE(F); 
  214.   end DUMP_TRANSITIONS; 
  215.  
  216.  
  217.   -- epsclosure - construct the epsilon closure of a set of ndfa states
  218.   --
  219.   -- NOTES
  220.   --    the epsilon closure is the set of all states reachable by an arbitrary
  221.   --  number of epsilon transitions which themselves do not have epsilon
  222.   --  transitions going out, unioned with the set of states which have non-null
  223.   --  accepting numbers.  t is an array of size numstates of nfa state numbers.
  224. --  Upon return, t holds the epsilon closure and numstates is updated.  accset
  225.   --  holds a list of the accepting numbers, and the size of accset is given
  226.   --  by nacc.  t may be subjected to reallocation if it is not large enough
  227.   --  to hold the epsilon closure.
  228.   --
  229.   --    hashval is the hash value for the dfa corresponding to the state set
  230.  
  231.   procedure EPSCLOSURE(T                  : in out INT_PTR; 
  232.                        NS_ADDR            : in out INTEGER; 
  233.                        ACCSET             : in out INT_PTR; 
  234.                        NACC_ADDR, HV_ADDR : out INTEGER; 
  235.                        RESULT             : out INT_PTR) is 
  236.     NS, TSP                                      : INTEGER; 
  237.     NUMSTATES, NACC, HASHVAL, TRANSSYM, NFACCNUM : INTEGER; 
  238.     STKEND                                       : INTEGER; 
  239.     STKPOS                                       : INTEGER; 
  240.     procedure MARK_STATE(STATE : in INTEGER) is 
  241.     begin
  242.       TRANS1(STATE) := TRANS1(STATE) - MARKER_DIFFERENCE; 
  243.     end MARK_STATE; 
  244.     pragma INLINE(MARK_STATE); 
  245.  
  246.     function IS_MARKED(STATE : in INTEGER) return BOOLEAN is 
  247.     begin
  248.       return TRANS1(STATE) < 0; 
  249.     end IS_MARKED; 
  250.     pragma INLINE(IS_MARKED); 
  251.  
  252.     procedure UNMARK_STATE(STATE : in INTEGER) is 
  253.     begin
  254.       TRANS1(STATE) := TRANS1(STATE) + MARKER_DIFFERENCE; 
  255.     end UNMARK_STATE; 
  256.     pragma INLINE(UNMARK_STATE); 
  257.  
  258.  
  259.     procedure CHECK_ACCEPT(STATE : in INTEGER) is 
  260.     begin
  261.       NFACCNUM := ACCPTNUM(STATE); 
  262.       if (NFACCNUM /= NIL) then 
  263.         NACC := NACC + 1; 
  264.         ACCSET(NACC) := NFACCNUM; 
  265.       end if; 
  266.     end CHECK_ACCEPT; 
  267.     pragma INLINE(CHECK_ACCEPT); 
  268.  
  269.     procedure DO_REALLOCATION is 
  270.     begin
  271.       CURRENT_MAX_DFA_SIZE := CURRENT_MAX_DFA_SIZE + MAX_DFA_SIZE_INCREMENT; 
  272.       NUM_REALLOCS := NUM_REALLOCS + 1; 
  273.       REALLOCATE_INTEGER_ARRAY(T, CURRENT_MAX_DFA_SIZE); 
  274.       REALLOCATE_INTEGER_ARRAY(STK, CURRENT_MAX_DFA_SIZE); 
  275.     end DO_REALLOCATION; 
  276.     pragma INLINE(DO_REALLOCATION); 
  277.  
  278.  
  279.     procedure PUT_ON_STACK(STATE : in INTEGER) is 
  280.     begin
  281.       STKEND := STKEND + 1; 
  282.       if (STKEND >= CURRENT_MAX_DFA_SIZE) then 
  283.         DO_REALLOCATION; 
  284.       end if; 
  285.       STK(STKEND) := STATE; 
  286.       MARK_STATE(STATE); 
  287.     end PUT_ON_STACK; 
  288.     pragma INLINE(PUT_ON_STACK); 
  289.  
  290.     procedure ADD_STATE(STATE : in INTEGER) is 
  291.     begin
  292.       NUMSTATES := NUMSTATES + 1; 
  293.       if (NUMSTATES >= CURRENT_MAX_DFA_SIZE) then 
  294.         DO_REALLOCATION; 
  295.       end if; 
  296.       T(NUMSTATES) := STATE; 
  297.       HASHVAL := HASHVAL + STATE; 
  298.     end ADD_STATE; 
  299.     pragma INLINE(ADD_STATE); 
  300.  
  301.     procedure STACK_STATE(STATE : in INTEGER) is 
  302.     begin
  303.       PUT_ON_STACK(STATE); 
  304.       CHECK_ACCEPT(STATE); 
  305.       if ((NFACCNUM /= NIL) or (TRANSCHAR(STATE) /= SYM_EPSILON)) then 
  306.         ADD_STATE(STATE); 
  307.       end if; 
  308.     end STACK_STATE; 
  309.     pragma INLINE(STACK_STATE); 
  310.  
  311.   begin
  312.     NUMSTATES := NS_ADDR; 
  313.     if (not DID_STK_INIT) then 
  314.       STK := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFA_SIZE); 
  315.       DID_STK_INIT := TRUE; 
  316.     end if; 
  317.  
  318.     NACC := 0; 
  319.     STKEND := 0; 
  320.     HASHVAL := 0; 
  321.  
  322.     for NSTATE in 1 .. NUMSTATES loop
  323.       NS := T(NSTATE); 
  324.  
  325.       -- the state could be marked if we've already pushed it onto
  326.       -- the stack
  327.       if (not IS_MARKED(NS)) then 
  328.         PUT_ON_STACK(NS); 
  329.         null; 
  330.       end if; 
  331.  
  332.       CHECK_ACCEPT(NS); 
  333.       HASHVAL := HASHVAL + NS; 
  334.     end loop; 
  335.  
  336.  
  337.     STKPOS := 1; 
  338.     while (STKPOS <= STKEND) loop
  339.       NS := STK(STKPOS); 
  340.       TRANSSYM := TRANSCHAR(NS); 
  341.  
  342.       if (TRANSSYM = SYM_EPSILON) then 
  343.         TSP := TRANS1(NS) + MARKER_DIFFERENCE; 
  344.  
  345.         if (TSP /= NO_TRANSITION) then 
  346.           if (not IS_MARKED(TSP)) then 
  347.             STACK_STATE(TSP); 
  348.           end if; 
  349.  
  350.           TSP := TRANS2(NS); 
  351.  
  352.           if (TSP /= NO_TRANSITION) then 
  353.             if (not IS_MARKED(TSP)) then 
  354.               STACK_STATE(TSP); 
  355.             end if; 
  356.           end if; 
  357.         end if; 
  358.       end if; 
  359.       STKPOS := STKPOS + 1; 
  360.     end loop; 
  361.  
  362.     -- clear out "visit" markers
  363.     for CHK_STKPOS in 1 .. STKEND loop
  364.       if (IS_MARKED(STK(CHK_STKPOS))) then 
  365.         UNMARK_STATE(STK(CHK_STKPOS)); 
  366.       else 
  367.         MISC.AFLEXFATAL("consistency check failed in epsclosure()"); 
  368.       end if; 
  369.     end loop; 
  370.  
  371.     NS_ADDR := NUMSTATES; 
  372.     HV_ADDR := HASHVAL; 
  373.     NACC_ADDR := NACC; 
  374.  
  375.     RESULT := T; 
  376.   end EPSCLOSURE; 
  377.  
  378.  
  379.   -- increase_max_dfas - increase the maximum number of DFAs
  380.  
  381.   procedure INCREASE_MAX_DFAS is 
  382.   begin
  383.     CURRENT_MAX_DFAS := CURRENT_MAX_DFAS + MAX_DFAS_INCREMENT; 
  384.  
  385.     NUM_REALLOCS := NUM_REALLOCS + 1; 
  386.  
  387.     REALLOCATE_INTEGER_ARRAY(BASE, CURRENT_MAX_DFAS); 
  388.     REALLOCATE_INTEGER_ARRAY(DEF, CURRENT_MAX_DFAS); 
  389.     REALLOCATE_INTEGER_ARRAY(DFASIZ, CURRENT_MAX_DFAS); 
  390.     REALLOCATE_INTEGER_ARRAY(ACCSIZ, CURRENT_MAX_DFAS); 
  391.     REALLOCATE_INTEGER_ARRAY(DHASH, CURRENT_MAX_DFAS); 
  392.     REALLOCATE_INT_PTR_ARRAY(DSS, CURRENT_MAX_DFAS); 
  393.     REALLOCATE_DFAACC_UNION(DFAACC, CURRENT_MAX_DFAS); 
  394.   end INCREASE_MAX_DFAS; 
  395.  
  396.  
  397.   -- ntod - convert an ndfa to a dfa
  398.   --
  399.   --  creates the dfa corresponding to the ndfa we've constructed.  the
  400.   --  dfa starts out in state #1.
  401.  
  402.   procedure NTOD is 
  403.  
  404.     ACCSET                                             : INT_PTR; 
  405.     DS, NACC, NEWDS                                    : INTEGER; 
  406.     DUPLIST, TARGFREQ, TARGSTATE, STATE                : C_SIZE_ARRAY; 
  407.     SYMLIST                                            : C_SIZE_BOOL_ARRAY; 
  408.     HASHVAL, NUMSTATES, DSIZE                          : INTEGER; 
  409.     NSET, DSET                                         : INT_PTR; 
  410.     TARGPTR, TOTALTRANS, I, J, COMSTATE, COMFREQ, TARG : INTEGER; 
  411.     NUM_START_STATES, TODO_HEAD, TODO_NEXT             : INTEGER; 
  412.     SNSRESULT                                          : BOOLEAN; 
  413.     FULL_TABLE_TEMP_FILE                               : FILE_TYPE; 
  414.     BUF                                                : VSTRING; 
  415.     NUM_NXT_STATES                                     : INTEGER; 
  416.     use TEXT_IO; 
  417.  
  418.     -- this is so find_table_space(...) will know where to start looking in
  419.     -- chk/nxt for unused records for space to put in the state
  420.   begin
  421.     ACCSET := ALLOCATE_INTEGER_ARRAY(NUM_RULES + 1); 
  422.     NSET := ALLOCATE_INTEGER_ARRAY(CURRENT_MAX_DFA_SIZE); 
  423.  
  424.     -- the "todo" queue is represented by the head, which is the DFA
  425.     -- state currently being processed, and the "next", which is the
  426.     -- next DFA state number available (not in use).  We depend on the
  427.     -- fact that snstods() returns DFA's \in increasing order/, and thus
  428.     -- need only know the bounds of the dfas to be processed.
  429.     TODO_HEAD := 0; 
  430.     TODO_NEXT := 0; 
  431.  
  432.     for CNT in 0 .. CSIZE loop
  433.       DUPLIST(CNT) := NIL; 
  434.       SYMLIST(CNT) := FALSE; 
  435.     end loop; 
  436.  
  437.     for CNT in 0 .. NUM_RULES loop
  438.       ACCSET(CNT) := NIL; 
  439.     end loop; 
  440.  
  441.     if (TRACE) then 
  442.       NFA.DUMPNFA(SCSET(1)); 
  443.       TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  444.       TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  445.       TEXT_IO.PUT(STANDARD_ERROR, "DFA Dump:"); 
  446.       TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  447.       TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  448.     end if; 
  449.  
  450.     TBLCMP.INITTBL; 
  451.  
  452.     if (FULLTBL) then 
  453.       GEN.DO_SECT3_OUT; 
  454.  
  455.       -- output user code up to ##
  456.       SKELETON_MANAGER.SKELOUT; 
  457.  
  458.       -- declare it "short" because it's a real long-shot that that
  459.       -- won't be large enough
  460.       begin -- make a temporary file to write yy_nxt array into
  461.         CREATE(FULL_TABLE_TEMP_FILE, OUT_FILE); 
  462.       exception
  463.         when USE_ERROR | NAME_ERROR => 
  464.           MISC.AFLEXFATAL("can't create temporary file"); 
  465.       end; 
  466.  
  467.       NUM_NXT_STATES := 1; 
  468.       TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, "( "); 
  469.       -- generate 0 entries for state #0
  470.       for CNT in 0 .. NUMECS loop
  471.         MISC.MK2DATA(FULL_TABLE_TEMP_FILE, 0); 
  472.       end loop; 
  473.  
  474.       TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, " )"); 
  475.       -- force extra blank line next dataflush()
  476.       DATALINE := NUMDATALINES; 
  477.     end if; 
  478.  
  479.     -- create the first states
  480.  
  481.     NUM_START_STATES := LASTSC*2; 
  482.  
  483.     for CNT in 1 .. NUM_START_STATES loop
  484.       NUMSTATES := 1; 
  485.  
  486.       -- for each start condition, make one state for the case when
  487.       -- we're at the beginning of the line (the '%' operator) and
  488.       -- one for the case when we're not
  489.  
  490.       if (CNT mod 2 = 1) then 
  491.         NSET(NUMSTATES) := SCSET((CNT/2) + 1); 
  492.       else 
  493.         NSET(NUMSTATES) := NFA.MKBRANCH(SCBOL(CNT/2), SCSET(CNT/2)); 
  494.       end if; 
  495.  
  496.       DFA.EPSCLOSURE(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, NSET); 
  497.  
  498.       SNSTODS(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, DS, SNSRESULT); 
  499.       if (SNSRESULT) then 
  500.         NUMAS := NUMAS + NACC; 
  501.         TOTNST := TOTNST + NUMSTATES; 
  502.         TODO_NEXT := TODO_NEXT + 1; 
  503.  
  504.         if (VARIABLE_TRAILING_CONTEXT_RULES and (NACC > 0)) then 
  505.           CHECK_TRAILING_CONTEXT(NSET, NUMSTATES, ACCSET, NACC); 
  506.         end if; 
  507.       end if; 
  508.     end loop; 
  509.  
  510.     SNSTODS(NSET, 0, ACCSET, 0, 0, END_OF_BUFFER_STATE, SNSRESULT); 
  511.     if (not SNSRESULT) then 
  512.       MISC.AFLEXFATAL("could not create unique end-of-buffer state"); 
  513.     end if; 
  514.     NUMAS := NUMAS + 1; 
  515.     NUM_START_STATES := NUM_START_STATES + 1; 
  516.     TODO_NEXT := TODO_NEXT + 1; 
  517.  
  518.     while (TODO_HEAD < TODO_NEXT) loop
  519.       NUM_NXT_STATES := NUM_NXT_STATES + 1; 
  520.       TARGPTR := 0; 
  521.       TOTALTRANS := 0; 
  522.  
  523.       for STATE_CNT in 1 .. NUMECS loop
  524.         STATE(STATE_CNT) := 0; 
  525.       end loop; 
  526.  
  527.       TODO_HEAD := TODO_HEAD + 1; 
  528.       DS := TODO_HEAD; 
  529.  
  530.       DSET := DSS(DS); 
  531.       DSIZE := DFASIZ(DS); 
  532.  
  533.       if (TRACE) then 
  534.         TEXT_IO.PUT(STANDARD_ERROR, "state # "); 
  535.         INT_IO.PUT(STANDARD_ERROR, DS, 1); 
  536.         TEXT_IO.PUT_LINE(STANDARD_ERROR, ":"); 
  537.       end if; 
  538.  
  539.       SYMPARTITION(DSET, DSIZE, SYMLIST, DUPLIST); 
  540.  
  541.       for SYM in 1 .. NUMECS loop
  542.         if (SYMLIST(SYM)) then 
  543.           SYMLIST(SYM) := FALSE; 
  544.  
  545.           if (DUPLIST(SYM) = NIL) then 
  546.           -- symbol has unique out-transitions
  547.             NUMSTATES := SYMFOLLOWSET(DSET, DSIZE, SYM, NSET); 
  548.             DFA.EPSCLOSURE(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, NSET); 
  549.  
  550.             SNSTODS(NSET, NUMSTATES, ACCSET, NACC, HASHVAL, NEWDS, SNSRESULT); 
  551.             if (SNSRESULT) then 
  552.               TOTNST := TOTNST + NUMSTATES; 
  553.               TODO_NEXT := TODO_NEXT + 1; 
  554.               NUMAS := NUMAS + NACC; 
  555.  
  556.               if (VARIABLE_TRAILING_CONTEXT_RULES and (NACC > 0)) then 
  557.                 CHECK_TRAILING_CONTEXT(NSET, NUMSTATES, ACCSET, NACC); 
  558.               end if; 
  559.             end if; 
  560.  
  561.             STATE(SYM) := NEWDS; 
  562.  
  563.             if (TRACE) then 
  564.               TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
  565.               INT_IO.PUT(STANDARD_ERROR, SYM, 1); 
  566.               TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
  567.               INT_IO.PUT(STANDARD_ERROR, NEWDS, 1); 
  568.               TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  569.             end if; 
  570.  
  571.             TARGPTR := TARGPTR + 1; 
  572.             TARGFREQ(TARGPTR) := 1; 
  573.             TARGSTATE(TARGPTR) := NEWDS; 
  574.             NUMUNIQ := NUMUNIQ + 1; 
  575.           else 
  576.           -- sym's equivalence class has the same transitions
  577.           -- as duplist(sym)'s equivalence class
  578.  
  579.             TARG := STATE(DUPLIST(SYM)); 
  580.             STATE(SYM) := TARG; 
  581.             if (TRACE) then 
  582.               TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
  583.               INT_IO.PUT(STANDARD_ERROR, SYM, 1); 
  584.               TEXT_IO.PUT(STANDARD_ERROR, ASCII.HT); 
  585.               INT_IO.PUT(STANDARD_ERROR, TARG, 1); 
  586.               TEXT_IO.NEW_LINE(STANDARD_ERROR); 
  587.             end if; 
  588.  
  589.             -- update frequency count for destination state
  590.  
  591.             I := 1; 
  592.  
  593.             while (TARGSTATE(I) /= TARG) loop
  594.               I := I + 1; 
  595.             end loop; 
  596.  
  597.             TARGFREQ(I) := TARGFREQ(I) + 1; 
  598.             NUMDUP := NUMDUP + 1; 
  599.           end if; 
  600.  
  601.           TOTALTRANS := TOTALTRANS + 1; 
  602.           DUPLIST(SYM) := NIL; 
  603.         end if; 
  604.       end loop; 
  605.  
  606.       NUMSNPAIRS := NUMSNPAIRS + TOTALTRANS; 
  607.  
  608.       if (CASEINS and not USEECS) then 
  609.         I := CHARACTER'POS('A'); 
  610.         J := CHARACTER'POS('a'); 
  611.         while (I < CHARACTER'POS('Z')) loop
  612.           STATE(I) := STATE(J); 
  613.           I := I + 1; 
  614.           J := J + 1; 
  615.         end loop; 
  616.       end if; 
  617.  
  618.       if (DS > NUM_START_STATES) then 
  619.         CHECK_FOR_BACKTRACKING(DS, STATE); 
  620.       end if; 
  621.  
  622.       if (FULLTBL) then 
  623.       -- supply array's 0-element
  624.         TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, ","); 
  625.         MISC.DATAFLUSH(FULL_TABLE_TEMP_FILE); 
  626.         TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, "( "); 
  627.         if (DS = END_OF_BUFFER_STATE) then 
  628.           MISC.MK2DATA(FULL_TABLE_TEMP_FILE,  -END_OF_BUFFER_STATE); 
  629.         else 
  630.           MISC.MK2DATA(FULL_TABLE_TEMP_FILE, END_OF_BUFFER_STATE); 
  631.         end if; 
  632.  
  633.         for CNT in 1 .. NUMECS loop
  634.         -- jams are marked by negative of state number
  635.           if ((STATE(CNT) /= 0)) then 
  636.             MISC.MK2DATA(FULL_TABLE_TEMP_FILE, STATE(CNT)); 
  637.           else 
  638.             MISC.MK2DATA(FULL_TABLE_TEMP_FILE,  -DS); 
  639.           end if; 
  640.         end loop; 
  641.  
  642.         TEXT_IO.PUT(FULL_TABLE_TEMP_FILE, " )"); 
  643.         -- force extra blank line next dataflush()
  644.         DATALINE := NUMDATALINES; 
  645.       else 
  646.         if (DS = END_OF_BUFFER_STATE) then 
  647.         -- special case this state to make sure it does what it's
  648.         -- supposed to, i.e., jam on end-of-buffer
  649.           TBLCMP.STACK1(DS, 0, 0, JAMSTATE_CONST); 
  650.         else  -- normal, compressed state
  651.         -- determine which destination state is the most common, and
  652.         -- how many transitions to it there are
  653.           COMFREQ := 0; 
  654.           COMSTATE := 0; 
  655.  
  656.           for CNT in 1 .. TARGPTR loop
  657.             if (TARGFREQ(CNT) > COMFREQ) then 
  658.               COMFREQ := TARGFREQ(CNT); 
  659.               COMSTATE := TARGSTATE(CNT); 
  660.             end if; 
  661.           end loop; 
  662.  
  663.           TBLCMP.BLDTBL(STATE, DS, TOTALTRANS, COMSTATE, COMFREQ); 
  664.         end if; 
  665.       end if; 
  666.     end loop; 
  667.  
  668.     if (FULLTBL) then 
  669.       TEXT_IO.PUT("yy_nxt : constant array(0.."); 
  670.       INT_IO.PUT(NUM_NXT_STATES - 1, 1); 
  671.       TEXT_IO.PUT_LINE(" , character'first..character'last) of short :="); 
  672.       TEXT_IO.PUT_LINE("   ("); 
  673.  
  674.       RESET(FULL_TABLE_TEMP_FILE, IN_FILE); 
  675.       while (not END_OF_FILE(FULL_TABLE_TEMP_FILE)) loop
  676.         TSTRING.GET_LINE(FULL_TABLE_TEMP_FILE, BUF); 
  677.         TSTRING.PUT_LINE(BUF); 
  678.       end loop; 
  679.       DELETE(FULL_TABLE_TEMP_FILE); 
  680.  
  681.       MISC.DATAEND; 
  682.     else 
  683.       TBLCMP.CMPTMPS;  -- create compressed template entries
  684.  
  685.       -- create tables for all the states with only one out-transition
  686.       while (ONESP > 0) loop
  687.         TBLCMP.MK1TBL(ONESTATE(ONESP), ONESYM(ONESP), ONENEXT(ONESP), ONEDEF(
  688.           ONESP)); 
  689.         ONESP := ONESP - 1; 
  690.       end loop; 
  691.  
  692.       TBLCMP.MKDEFTBL; 
  693.     end if; 
  694.   end NTOD; 
  695.  
  696.   -- snstods - converts a set of ndfa states into a dfa state
  697.   --
  698.   -- on return, the dfa state number is in newds.
  699.   procedure SNSTODS(SNS           : in INT_PTR; 
  700.                     NUMSTATES     : in INTEGER; 
  701.                     ACCSET        : in INT_PTR; 
  702.                     NACC, HASHVAL : in INTEGER; 
  703.                     NEWDS_ADDR    : out INTEGER; 
  704.                     RESULT        : out BOOLEAN) is 
  705.     DIDSORT : BOOLEAN := FALSE; 
  706.     J       : INTEGER; 
  707.     NEWDS   : INTEGER; 
  708.     OLDSNS  : INT_PTR; 
  709.   begin
  710.     for I in 1 .. LASTDFA loop
  711.       if (HASHVAL = DHASH(I)) then 
  712.         if (NUMSTATES = DFASIZ(I)) then 
  713.           OLDSNS := DSS(I); 
  714.  
  715.           if (not DIDSORT) then 
  716.           -- we sort the states in sns so we can compare it to
  717.           -- oldsns quickly.  we use bubble because there probably
  718.           -- aren't very many states
  719.  
  720.             MISC.BUBBLE(SNS, NUMSTATES); 
  721.             DIDSORT := TRUE; 
  722.           end if; 
  723.  
  724.           J := 1; 
  725.           while (J <= NUMSTATES) loop
  726.             if (SNS(J) /= OLDSNS(J)) then 
  727.               exit; 
  728.             end if; 
  729.             J := J + 1; 
  730.           end loop; 
  731.  
  732.           if (J > NUMSTATES) then 
  733.             DFAEQL := DFAEQL + 1; 
  734.             NEWDS_ADDR := I; 
  735.             RESULT := FALSE; 
  736.             return; 
  737.           end if; 
  738.  
  739.           HSHCOL := HSHCOL + 1; 
  740.         else 
  741.           HSHSAVE := HSHSAVE + 1; 
  742.         end if; 
  743.       end if; 
  744.     end loop; 
  745.     -- make a new dfa
  746.  
  747.     LASTDFA := LASTDFA + 1; 
  748.     if (LASTDFA >= CURRENT_MAX_DFAS) then 
  749.       INCREASE_MAX_DFAS; 
  750.     end if; 
  751.  
  752.     NEWDS := LASTDFA; 
  753.  
  754.     DSS(NEWDS) := new UNBOUNDED_INT_ARRAY(0 .. NUMSTATES + 1); 
  755.  
  756.     -- if we haven't already sorted the states in sns, we do so now, so that
  757.     -- future comparisons with it can be made quickly
  758.  
  759.     if (not DIDSORT) then 
  760.       MISC.BUBBLE(SNS, NUMSTATES); 
  761.     end if; 
  762.  
  763.     for I in 1 .. NUMSTATES loop
  764.       DSS(NEWDS)(I) := SNS(I); 
  765.     end loop; 
  766.  
  767.     DFASIZ(NEWDS) := NUMSTATES; 
  768.     DHASH(NEWDS) := HASHVAL; 
  769.  
  770.     if (NACC = 0) then 
  771.       DFAACC(NEWDS).DFAACC_STATE := 0; 
  772.       ACCSIZ(NEWDS) := 0; 
  773.     else 
  774.     -- find lowest numbered rule so the disambiguating rule will work
  775.       J := NUM_RULES + 1; 
  776.  
  777.       for I in 1 .. NACC loop
  778.         if (ACCSET(I) < J) then 
  779.           J := ACCSET(I); 
  780.         end if; 
  781.       end loop; 
  782.  
  783.       DFAACC(NEWDS).DFAACC_STATE := J; 
  784.     end if; 
  785.  
  786.     NEWDS_ADDR := NEWDS; 
  787.     RESULT := TRUE; 
  788.     return; 
  789.  
  790.   exception
  791.     when STORAGE_ERROR => 
  792.       MISC.AFLEXFATAL("dynamic memory failure in snstods()"); 
  793.   end SNSTODS; 
  794.  
  795.   -- symfollowset - follow the symbol transitions one step
  796.   function SYMFOLLOWSET(DS              : in INT_PTR; 
  797.                         DSIZE, TRANSSYM : in INTEGER; 
  798.                         NSET            : in INT_PTR) return INTEGER is 
  799.     NS, TSP, SYM, LENCCL, CH, NUMSTATES, CCLLIST : INTEGER; 
  800.   begin
  801.     NUMSTATES := 0; 
  802.  
  803.     for I in 1 .. DSIZE loop
  804.     -- for each nfa state ns in the state set of ds
  805.       NS := DS(I); 
  806.       SYM := TRANSCHAR(NS); 
  807.       TSP := TRANS1(NS); 
  808.  
  809.       if (SYM < 0) then 
  810.       -- it's a character class
  811.         SYM :=  -SYM; 
  812.         CCLLIST := CCLMAP(SYM); 
  813.         LENCCL := CCLLEN(SYM); 
  814.  
  815.         if (CCLNG(SYM) /= 0) then 
  816.           for J in 0 .. LENCCL - 1 loop
  817.           -- loop through negated character class
  818.             CH := CHARACTER'POS(CCLTBL(CCLLIST + J)); 
  819.  
  820.             if (CH > TRANSSYM) then 
  821.               exit;  -- transsym isn't in negated ccl
  822.             else 
  823.               if (CH = TRANSSYM) then 
  824.                 goto BOTTOM;  -- next 2
  825.               end if; 
  826.             end if; 
  827.           end loop; 
  828.  
  829.           -- didn't find transsym in ccl
  830.           NUMSTATES := NUMSTATES + 1; 
  831.           NSET(NUMSTATES) := TSP; 
  832.         else 
  833.           for J in 0 .. LENCCL - 1 loop
  834.             CH := CHARACTER'POS(CCLTBL(CCLLIST + J)); 
  835.  
  836.             if (CH > TRANSSYM) then 
  837.               exit; 
  838.             else 
  839.               if (CH = TRANSSYM) then 
  840.                 NUMSTATES := NUMSTATES + 1; 
  841.                 NSET(NUMSTATES) := TSP; 
  842.                 exit; 
  843.               end if; 
  844.             end if; 
  845.           end loop; 
  846.         end if; 
  847.       else 
  848.         if ((SYM >= CHARACTER'POS('A')) and (SYM <= CHARACTER'POS('Z')) and 
  849.           CASEINS) then 
  850.           MISC.AFLEXFATAL("consistency check failed in symfollowset"); 
  851.         else 
  852.           if (SYM = SYM_EPSILON) then 
  853.             null;  -- do nothing
  854.           else 
  855.             if (ECGROUP(SYM) = TRANSSYM) then 
  856.               NUMSTATES := NUMSTATES + 1; 
  857.               NSET(NUMSTATES) := TSP; 
  858.             end if; 
  859.           end if; 
  860.         end if; 
  861.       end if; 
  862.  
  863.       <<BOTTOM>> null; 
  864.     end loop; 
  865.     return NUMSTATES; 
  866.   end SYMFOLLOWSET; 
  867.  
  868.   -- sympartition - partition characters with same out-transitions
  869.   procedure SYMPARTITION(DS        : in INT_PTR; 
  870.                          NUMSTATES : in INTEGER; 
  871.                          SYMLIST   : in out C_SIZE_BOOL_ARRAY; 
  872.                          DUPLIST   : in out C_SIZE_ARRAY) is 
  873.     TCH, J, NS, LENCCL, CCLP, ICH : INTEGER; 
  874.     DUPFWD                        : C_SIZE_ARRAY; 
  875.  
  876.   -- partitioning is done by creating equivalence classes for those
  877.   -- characters which have out-transitions from the given state.  Thus
  878.   -- we are really creating equivalence classes of equivalence classes.
  879.   begin
  880.     for I in 1 .. NUMECS loop
  881.     -- initialize equivalence class list
  882.       DUPLIST(I) := I - 1; 
  883.       DUPFWD(I) := I + 1; 
  884.     end loop; 
  885.  
  886.     DUPLIST(1) := NIL; 
  887.     DUPFWD(NUMECS) := NIL; 
  888.     DUPFWD(0) := 0; 
  889.  
  890.     for I in 1 .. NUMSTATES loop
  891.       NS := DS(I); 
  892.       TCH := TRANSCHAR(NS); 
  893.  
  894.       if (TCH /= SYM_EPSILON) then 
  895.         if ((TCH <  -LASTCCL) or (TCH > CSIZE)) then 
  896.           MISC.AFLEXFATAL("bad transition character detected in sympartition()")
  897.             ; 
  898.         end if; 
  899.  
  900.         if (TCH > 0) then 
  901.         -- character transition
  902.           ECS.MKECHAR(ECGROUP(TCH), DUPFWD, DUPLIST); 
  903.           SYMLIST(ECGROUP(TCH)) := TRUE; 
  904.         else 
  905.         -- character class
  906.           TCH :=  -TCH; 
  907.  
  908.           LENCCL := CCLLEN(TCH); 
  909.           CCLP := CCLMAP(TCH); 
  910.           ECS.MKECCL(CCLTBL(CCLP .. CCLP + LENCCL), LENCCL, DUPFWD, DUPLIST, 
  911.             NUMECS); 
  912.  
  913.           if (CCLNG(TCH) /= 0) then 
  914.             J := 0; 
  915.  
  916.             for K in 0 .. LENCCL - 1 loop
  917.               ICH := CHARACTER'POS(CCLTBL(CCLP + K)); 
  918.  
  919.               J := J + 1; 
  920.               while (J < ICH) loop
  921.                 SYMLIST(J) := TRUE; 
  922.                 J := J + 1; 
  923.               end loop; 
  924.             end loop; 
  925.  
  926.             J := J + 1; 
  927.             while (J <= NUMECS) loop
  928.               SYMLIST(J) := TRUE; 
  929.               J := J + 1; 
  930.             end loop; 
  931.           else 
  932.             for K in 0 .. LENCCL - 1 loop
  933.               ICH := CHARACTER'POS(CCLTBL(CCLP + K)); 
  934.               SYMLIST(ICH) := TRUE; 
  935.             end loop; 
  936.           end if; 
  937.         end if; 
  938.       end if; 
  939.     end loop; 
  940.   end SYMPARTITION; 
  941. end DFA; 
  942.